package pap;

import pap.utils.UncompatibleDimensionsException;

public class Vector {
	protected final Point point;
	Double magnitude = null;

	/**
	 * Instance a new Vector as the oriented segment starting at the origin of
	 * axis and terminating at the Point point
	 * 
	 * @param point
	 *            the end point of the Vector
	 */
	public Vector(Point point) {
		this.point = point;
	}

	/**
	 * Instance a new Vector with the specified parameters.
	 * 
	 * @param degrees
	 * @param magnitude
	 */
	public Vector(double degrees, double magnitude) {

		double angleRadians = Math.toRadians(degrees);

		this.point = new Point(new double[] {
				Math.sin(angleRadians) * magnitude,
				Math.cos(angleRadians) * magnitude });
		this.magnitude = magnitude;
	}

	public double getMagnitude() {
		if (magnitude == null)
			magnitude = point.distanceFromOrigin();

		return magnitude;
	}

	public Vector reverse() {
		return multiply(-1);
	}

	public Vector getDirection() {
		if (getMagnitude() == 0)
			return new Vector(new Point(new double[] { 0, 0 }));

		return divide(getMagnitude());
	}

	/**
	 * Multiplies the current Vector by the value val
	 * 
	 * @param val
	 * @return a new vector as the multiplication result
	 */
	public Vector multiply(double val) {
		double[] newCoords = new double[point.getDimension()];

		for (int i = 0; i < point.getDimension(); i++)
			newCoords[i] = point.getCoordinate(i) * val;

		return new Vector(new Point(newCoords));
	}

	/**
	 * Divides the current Vector by the value val
	 * 
	 * @param val
	 * @return a new vector as the division result
	 */
	public Vector divide(double val) {

		return multiply(1 / val);
	}

	/**
	 * Sum between the current Vector and the Vector v
	 * 
	 * @param v
	 * @return a new Vector as the result of the sum
	 * @throws UncompatibleDimensionsException
	 */
	public Vector sum(Vector v) throws UncompatibleDimensionsException {

		return new Vector(applyAt(v.getPoint()));
	}

	/**
	 * Sum between the current Vector's point and the Point p
	 * 
	 * @param p
	 * @return a new Point as the result of the sum
	 * @throws UncompatibleDimensionsException
	 */
	public Point applyAt(Point p) throws UncompatibleDimensionsException {
		int dimension = p.getDimension();

		if (dimension != point.getDimension())
			throw new UncompatibleDimensionsException();

		double[] newCoords = new double[dimension];

		for (int i = 0; i < dimension; i++)
			newCoords[i] = p.getCoordinate(i) + point.getCoordinate(i);

		return new Point(newCoords);

	}

	/**
	 * Calculates the vector that connects the two specified points.
	 * 
	 * @param from
	 * @param to
	 * @return a vector
	 * @throws UncompatibleDimensionsException
	 */
	public static Vector vectorConnectingPoints(Point from, Point to)
			throws UncompatibleDimensionsException {
		int dimension = from.getDimension();

		if (dimension != to.getDimension())
			throw new UncompatibleDimensionsException();

		double[] newCoords = new double[dimension];

		for (int i = 0; i < dimension; i++)
			newCoords[i] = from.getCoordinate(i) - to.getCoordinate(i);

		return new Vector(new Point(newCoords));
	}

	public Point getPoint() {
		return point;
	}
}